package chen.huai.jie.spring.xmlconfig.mybatis;

import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.SelectKey;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;

import javax.persistence.GeneratedValue;
import java.lang.reflect.Method;

public class KeyBuilder {
    private Configuration configuration;
    private MapperBuilderAssistant assistant;
    private KeyGenerator keyGenerator;
    private String keyProperty = "id";
    private String keyColumn = null;

    public KeyBuilder(Configuration configuration, MapperBuilderAssistant assistant) {
        this.configuration = configuration;
        this.assistant = assistant;
    }

    public void buildKey(SqlCommandType sqlCommandType, Method method, String mappedStatementId, EntityPortray entityPortray, Options options, LanguageDriver languageDriver) {
        if (!SqlCommandType.INSERT.equals(sqlCommandType) && !SqlCommandType.UPDATE.equals(sqlCommandType)) {
            this.keyGenerator = new NoKeyGenerator();
        } else {
            this.keyProperty = entityPortray.getPrimaryProperty();
            SelectKey selectKey = (SelectKey) method.getAnnotation(SelectKey.class);
            if (selectKey != null) {
                this.keyGenerator = this.handleSelectKeyAnnotation(selectKey, mappedStatementId, MapperUtils.getParameterType(method), languageDriver);
                this.keyProperty = selectKey.keyProperty();
            } else if (options == null) {
                if (sqlCommandType == SqlCommandType.INSERT) {
                    this.keyGenerator = this.keyGeneratorFromEntity(entityPortray);
                }

                if (this.keyGenerator == null) {
                    this.keyGenerator = (KeyGenerator) (this.configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator());
                }
            } else {
                this.keyGenerator = (KeyGenerator) (options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator());
                this.keyProperty = options.keyProperty();
                this.keyColumn = options.keyColumn();
            }
        }

    }

    private KeyGenerator keyGeneratorFromEntity(EntityPortray entityPortray) {
        GeneratedValue generatedValue = entityPortray.getGeneratedValue();
        if (generatedValue != null) {
            String generator = generatedValue.generator();
            if (generator.equals("uuid") || generator.isEmpty()) {
                return new UuidGenerator();
            }
        }

        return null;
    }

    private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class<?> parameterTypeClass, LanguageDriver languageDriver) {
        String id = baseStatementId + "!selectKey";
        Class<?> resultTypeClass = selectKeyAnnotation.resultType();
        StatementType statementType = selectKeyAnnotation.statementType();
        String keyProperty = selectKeyAnnotation.keyProperty();
        String keyColumn = selectKeyAnnotation.keyColumn();
        boolean executeBefore = selectKeyAnnotation.before();
        boolean useCache = false;
        KeyGenerator keyGenerator = new NoKeyGenerator();
        Integer fetchSize = null;
        Integer timeout = null;
        boolean flushCache = false;
        String parameterMap = null;
        String resultMap = null;
        ResultSetType resultSetTypeEnum = null;
        SqlSource sqlSource = MapperUtils.buildSqlSourceFromStrings(this.configuration, selectKeyAnnotation.statement(), parameterTypeClass, languageDriver);
        SqlCommandType sqlCommandType = SqlCommandType.SELECT;
        this.assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, (Integer) fetchSize, (Integer) timeout, (String) parameterMap, parameterTypeClass, (String) resultMap, resultTypeClass, (ResultSetType) resultSetTypeEnum, flushCache, useCache, false, keyGenerator, keyProperty, keyColumn, (String) null, languageDriver, (String) null);
        id = this.assistant.applyCurrentNamespace(id, false);
        MappedStatement keyStatement = this.configuration.getMappedStatement(id, false);
        SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
        this.configuration.addKeyGenerator(id, answer);
        return answer;
    }

    public KeyGenerator getKeyGenerator() {
        return this.keyGenerator;
    }

    public String getKeyProperty() {
        return this.keyProperty;
    }

    public String getKeyColumn() {
        return this.keyColumn;
    }
}
